﻿#region File and License Information
/*
<File>
	<Copyright>Copyright © 2007, Daniel Vaughan. All rights reserved.</Copyright>
	<License see="prj:///Documentation/License.txt"/>
	<Owner Name="Daniel Vaughan" Email="dbvaughan@gmail.com"/>
	<CreationDate>2009-04-15 21:47:56Z</CreationDate>
	<LastSubmissionDate>$Date: $</LastSubmissionDate>
	<Version>$Revision: $</Version>
</File>
*/
#endregion

using System;
using System.IO;
using System.Windows;
using System.Windows.Threading;

using Microsoft.Win32;

using log4net;

using DanielVaughan.ComponentModel;
using DanielVaughan.Data;
using DanielVaughan.Gui;
using DanielVaughan.IO;
using DanielVaughan.Resources;

namespace DanielVaughan.Services
{
	/// <summary>
	/// Default implementation of <see cref="IFileService"/>.
	/// </summary>
	public class FileService : IFileService
	{
		static readonly ILog log = LogManager.GetLogger(typeof(FileService));

		public FileOperationResult SaveAs(string fileName, FileOperationHandler operationHandler,
			FileErrorAction fileErrorAction)
		{
			ArgumentValidator.AssertNotNull(operationHandler, "operationHandler");

			var shell = ServiceLocatorSingleton.Instance.GetInstance<IMainWindow>() as Window;
			var dialog = new SaveFileDialog();
			/* TODO: Customize the save dialog. */
			dialog.FileName = fileName;
			if (!dialog.ShowDialog(shell).Value)
			{
				return FileOperationResult.Cancelled;
			}
			return Save(dialog.FileName, operationHandler, fileErrorAction);
		}

		public FileOperationResult Save(string fileName, FileOperationHandler operationHandler, 
			FileErrorAction fileErrorAction)
		{
			ArgumentValidator.AssertNotNullOrEmpty(fileName, "fileName");
			ArgumentValidator.AssertNotNull(operationHandler, "operationHandler");

			FileErrorAction actualFileErrorAction = fileErrorAction;

			string userMessage = null;
			bool ioExceptionOccured = false;
			try
			{
				operationHandler(fileName);
				return FileOperationResult.Successful;
			}
			catch (IOException ex)
			{
				log.Info("Unable to save file: " + fileName, ex);
				userMessage = "A problem occured saving the file."; /* TODO: Make localizable resource. */
				ioExceptionOccured = true;
			}
			catch (Exception ex) /* TODO: catch common IO errors and report to user. */
			{
				log.Info("Unable to save file: " + fileName, ex);
				var userMessageException = ex as IUserMessageProvider;
				if (userMessageException != null && userMessageException.UserMessagePresent)
				{
					userMessage = userMessageException.UserMessage;
				}
			}

			if (!ioExceptionOccured)
			{
				if (fileErrorAction == FileErrorAction.UseAlternative)
				{	/* If this wasn't an IOException then we do not allow the user to select an alternative. */
					actualFileErrorAction = FileErrorAction.InformOnly;
				}
			}

			var result = FileOperationResult.Failed;

			var messageService = ServiceLocatorSingleton.Instance.GetInstance<IMessageService>();

			switch (actualFileErrorAction)
			{
				case FileErrorAction.UseAlternative:
					messageService.ShowError(userMessage, StringResources.Services_FileService_UnableToSaveFile);
					do
					{
						result = SaveAs(fileName, operationHandler, FileErrorAction.InformOnly);
					} while (result != FileOperationResult.Successful && result != FileOperationResult.Cancelled);
					break;
				case FileErrorAction.InformOnly:
					messageService.ShowError(userMessage, StringResources.Services_FileService_UnableToSaveFile);
					break;
			}
			return result;
		}

		public FileOperationResult Open(FileOperationHandler operationHandler,
			FileErrorAction fileErrorAction, string dialogFilter)
		{
			ArgumentValidator.AssertNotNull(operationHandler, "operationHandler");
			return Open(null, operationHandler, fileErrorAction, dialogFilter);
		}

		public FileOperationResult Open(string filePath, FileOperationHandler operationHandler,
			FileErrorAction fileErrorAction, string dialogFilter)
		{
			ArgumentValidator.AssertNotNull(operationHandler, "operationHandler");

			string fileNameToUse = filePath;
			if (!File.Exists(filePath))
			{
				var shell = ServiceLocatorSingleton.Instance.GetInstance<IMainWindow>() as Window;
				FileOperationResult result = FileOperationResult.Successful;
				var dispatcher = ServiceLocatorSingleton.Instance.GetInstance<Dispatcher>();
				dispatcher.InvokeIfRequired(delegate
				{
					var dialog = new OpenFileDialog();
					/* TODO: Customize the save dialog. */
					dialog.Title = "Choose file name";
					dialog.Filter = dialogFilter;
					if (!dialog.ShowDialog(shell).Value)
					{
						result = FileOperationResult.Cancelled;
						return;
					}
					fileNameToUse = dialog.FileName;
				});
				if (result != FileOperationResult.Successful)
				{
					return result;
				}
			}

			string userMessage = null;
			try
			{
				operationHandler(fileNameToUse);
				return FileOperationResult.Successful;
			}
			catch (MementoIncompatibilityException ex)
			{
				userMessage = string.Format(StringResources.Services_FileService_FileCreatedInNewerVersion, fileNameToUse);
				log.Info("Unable to open file: " + filePath, ex);
			}
			catch (Exception ex) /* TODO: catch common IO errors and report to user. */
			{
				log.Info("Unable to open file: " + filePath, ex);
			}

			if (userMessage == null)
			{
				userMessage = string.Format(StringResources.Services_FileService_UnableToOpenFile, fileNameToUse);
			}

			var messageService = ServiceLocatorSingleton.Instance.GetInstance<IMessageService>();

			switch (fileErrorAction)
			{
				case FileErrorAction.UseAlternative:
					messageService.ShowWarning(userMessage);
					var result = Open(null, operationHandler, FileErrorAction.UseAlternative, dialogFilter);
					return result;
				case FileErrorAction.InformOnly:
					messageService.ShowWarning(userMessage);
					break;
			}
			return FileOperationResult.Failed;
		}

	}
}
